/** @jsx html */
import {DomEditor, IDomEditor, SlateDescendant} from "@wangeditor/editor";
import {VNode} from 'snabbdom'
import {html} from 'snabbdom-jsx'
import {BaseElement} from "slate/dist/interfaces/element";
import WangeditorUtils from "../WangeditorUtils";

export interface IErrorReplaceData extends BaseElement {
  type: string;
  replaceWord: string;
  replaceOldWord: string;
  replaceId: string;
}


export const errorReplace: IErrorReplaceData = {
  type: 'errorReplace',
  replaceWord: '',
  replaceOldWord: '',
  replaceId: '',
  children: [{text: ''}],  // void 元素必须有一个 children ，其中只有一个空字符串，重要！！！
}

function errorReplaceWithAttachment<T extends IDomEditor>(editor: T) {
  const {isInline, isVoid} = editor
  const newEditor = editor

  newEditor.isInline = (elem) => {
    const type = DomEditor.getNodeType(elem)
    if (type === errorReplace.type) return true // 针对 type: errorReplace ，设置为 inline
    return isInline(elem)
  }

  newEditor.isVoid = (elem) => {
    const type = DomEditor.getNodeType(elem)
    if (type === errorReplace.type) return false
    return isVoid(elem)
  }

  return newEditor // 返回 newEditor ，重要！！！
}

function errorReplaceRenderAttachment(elem: IErrorReplaceData, children: VNode[] | null, editor: IDomEditor): VNode {
  const clickFuntion = (replace = true, e) => {
    e.stopPropagation()
    let html = editor.toDOMNode(elem)
    editor.scrollToElem(html.id)
    let path = WangeditorUtils.replaceNode(
      elem,
      editor,
      replace ? elem.replaceWord : elem.replaceOldWord
    )
    editor.emit(errorReplace.type, elem, path, replace)
  }

  // @ts-ignore
  const attachVnode: VNode = (
    <div data-replace-word={elem.replaceWord}
         data-replace-old-word={elem.replaceOldWord}
         data-replace-id={elem.replaceId}
         data-node={elem}
         className="zhixinErrorReplace">
      {...children}
      <div className="errorReplacePanel">
        <div className="errorReplaceDiv" contentEditable="false" onclick={(e) => clickFuntion(true, e)}>
          {`建议文字替换为：${elem.replaceWord}`}
        </div>
        <div className="errorNoReplaceDiv" contentEditable="false" onclick={(e) => clickFuntion(false, e)}>
          {''}
        </div>
      </div>
    </div>
  )

  return attachVnode
}

function errorReplaceAttachmentToHtml(elem: IErrorReplaceData, childrenHtml: string): string {
  // 获取附件元素的数据
  const {replaceWord = ''} = elem
  // 生成 HTML 代码
  const html = `<span
        data-w-e-type="${errorReplace.type}"
        data-w-e-is-inline
        data-replace-word="${replaceWord}"
        data-replace-old-word="${elem.replaceOldWord}"
        data-replace-id="${elem.replaceId}"
    >${childrenHtml}</span>`

  return html
}

/**
 * 解析 HTML 字符串，生成“附件”元素
 * @param domElem HTML 对应的 DOM Element
 * @param children 子节点
 * @param editor editor 实例
 * @returns “附件”元素，如上文的 myResume
 */
function errorReplaceParseAttachmentHtml(
  domElem: Element,
  children: SlateDescendant[],
  editor: IDomEditor
): IErrorReplaceData {
  // 从 DOM element 中获取“附件”的信息
  const replaceWord = domElem.getAttribute('data-replace-word') || ''
  const replaceOldWord = domElem.getAttribute('data-replace-old-word') || ''
  const replaceId = domElem.getAttribute('data-replace-id') || ''

  // 生成“附件”元素（按照此前约定的数据结构）
  const myResume: IErrorReplaceData = {
    type: errorReplace.type,
    replaceWord,
    replaceId,
    replaceOldWord,
    children, // void node 必须有 children ，其中有一个空字符串，重要！！！
  }

  return myResume
}

const ErrorReplaceModule = {
  editorPlugin: errorReplaceWithAttachment,
  renderElems: [
    {
      type: errorReplace.type, // 新元素 type ，重要！！！
      renderElem: errorReplaceRenderAttachment,
    }
  ],
  elemsToHtml: [
    {
      type: errorReplace.type, // 新元素 type ，重要！！！
      elemToHtml: errorReplaceAttachmentToHtml,
    }
  ],
  parseElemsHtml: [
    {
      selector: `span[data-w-e-type="${errorReplace.type}"]`, // CSS 选择器，匹配特定的 HTML 标签
      parseElemHtml: errorReplaceParseAttachmentHtml,
    }
  ]
}

/**
 * 用法，在编辑区的数据里面，需要替换的文字用这样包裹起来就行了，
 * <span data-w-e-type="errorReplace"
 * data-replace-id="66667"
 * data-replace-old-word="一万饭"
 * data-replace-word="一碗饭">一万饭</span>
 */
export default ErrorReplaceModule
